package com.chen.gui.component.field;

import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.FontMetrics;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseEvent;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JPopupMenu;
import javax.swing.event.MouseInputAdapter;
import javax.swing.text.BadLocationException;

import sun.swing.SwingUtilities2;

import com.chen.gui.component.button.CButton;
import com.chen.qq.Context;

public class CPasswordField extends JComponent {

	private static final long serialVersionUID = -3549201144506510817L;

	private CButton btnKeyboard = Context.getButton("keyboard.png");
	private Handler handler = new Handler();
	private KeyBoard keyBoard = new KeyBoard();
	private boolean mouseOver;
	private JPasswordField tf = new JPasswordField() {

		private static final long serialVersionUID = 1762488411241712951L;

		@Override
		protected void paintComponent(Graphics g) {
			super.paintComponent(g);
			if (!hasFocus() && getPassword().length == 0) {
				FontMetrics fm = getFontMetrics(getFont());
				Insets insets = getInsets();
				int x = insets.left + 1;
				int y = insets.top + fm.getAscent();
				g.setColor(Color.gray);
				g.drawString("请输入密码", x, y + 1);
			}
		}
	};

	public CPasswordField() {
		this.setLayout(new BorderLayout());
		this.add(tf);
		this.add(btnKeyboard, BorderLayout.EAST);
		tf.setBorder(null);
		this.setBorder(BorderFactory.createEtchedBorder());

		tf.addFocusListener(handler);
		tf.addMouseListener(handler);
		btnKeyboard.addActionListener(handler);
		JPopupMenu popup = new JPopupMenu();
		popup.add(keyBoard);
		popup.setBorder(null);
		btnKeyboard.setComponentPopupMenu(popup);
		btnKeyboard.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
	}

	@Override
	protected void paintBorder(Graphics g) {
		Graphics2D g2d = (Graphics2D) g;
		if (mouseOver) {
			g2d.setStroke(new BasicStroke(2f));
			g2d.setColor(Color.blue);
			g2d.drawRect(1, 1, getWidth() - 2, getHeight() - 2);
		} else {
			super.paintBorder(g);
		}
	}

	@Override
	public Dimension getPreferredSize() {
		return new Dimension(0, 25);
	}

	class KeyBoard extends JPanel {

		private static final long serialVersionUID = -710255736908883215L;

		private Color backColor = new Color(20, 155, 225);

		private boolean shift;

		private boolean caps;

		private boolean mouseOnClose;

		private Image imgClose = Context.getIcon("closeKeyboard.png").getImage();
		private Image imgClose2 = Context.getIcon("closeKeyboard2.png").getImage();

		public KeyBoard() {
			this.setLayout(new FlowLayout(FlowLayout.CENTER, 3, 3));
			setBackground(new Color(25, 120, 180));
			initKeys();
			this.addMouseMotionListener(handler);
			this.addMouseListener(handler);
		}

		private void initKeys() {
			add(new KeyBtn("`", "~"));
			add(new KeyBtn("1", "!"));
			add(new KeyBtn("2", "@"));
			add(new KeyBtn("3", "#"));
			add(new KeyBtn("4", "$"));
			add(new KeyBtn("5", "%"));
			add(new KeyBtn("6", "^"));
			add(new KeyBtn("7", "&"));
			add(new KeyBtn("8", "*"));
			add(new KeyBtn("9", "("));
			add(new KeyBtn("0", ")"));
			KeyBtn btnBack = new KeyBtn("←");
			btnBack.setBorder(BorderFactory.createEmptyBorder(0, 15, 0, 15));
			add(btnBack);

			add(new KeyBtn("Shift"));
			add(new KeyBtn("-", "_"));
			add(new KeyBtn("=", "+"));
			add(new KeyBtn("[", "{"));
			add(new KeyBtn("]", "}"));
			add(new KeyBtn(";", ":"));
			add(new KeyBtn("\'", "\""));
			add(new KeyBtn("\\", "|"));
			add(new KeyBtn(",", "<"));
			add(new KeyBtn(".", ">"));
			add(new KeyBtn("/", "?"));
			add(new KeyBtn("Caps Lock"));

			for (char i = 0; i < 26; i++) {
				add(new KeyBtn(String.valueOf((char) ('a' + i)), String.valueOf((char) ('A' + i))));
			}
		}

		private void shift() {
			shift = !shift;
			change();
		}

		private void caps() {
			caps = !caps;
			change();
		}

		private void change() {
			for (Component c : getComponents()) {
				KeyBtn btn = (KeyBtn) c;
				btn.changeText();
			}
		}

		@Override
		protected void paintComponent(Graphics g) {
			super.paintComponent(g);
			Graphics2D g2d = (Graphics2D) g;
			int x = getWidth() - 13;
			int y = 4;
			g2d.drawImage(mouseOnClose ? imgClose : imgClose2, x, y, 12, 12, null);
		}

		@Override
		public Dimension getPreferredSize() {
			return new Dimension(375, 112);
		}

		class KeyBtn extends JButton {

			private static final long serialVersionUID = -4399341229860893930L;

			private String c0;

			private String c1;

			private KeyBtn(String c0, String c1) {
				this(c0);
				this.c0 = c0;
				this.c1 = c1;
			}

			private KeyBtn(String text) {
				super(text);
				this.addActionListener(handler);
				this.setBorder(null);
			}

			private void changeText() {
				String text = getText();
				if (text.length() > 1 || text.equals("←"))
					return;

				if (text.toLowerCase().compareTo("a") >= 0 && text.toLowerCase().compareTo("z") <= 0)
					setText(!(shift ^ caps) ? c0 : c1);
				else
					setText(shift ? c1 : c0);
			}

			@Override
			protected void paintComponent(Graphics g) {
				int w = getWidth();
				int h = getHeight();

				Graphics2D g2d = (Graphics2D) g.create();
				g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
				g2d.setColor(Color.white);
				g2d.fillRoundRect(0, 0, w, h, 5, 5);

				if (getModel().isPressed())
					g2d.translate(1, 1);

				String text = getText();
				if (text.equals("Shift") && shift || text.equals("Caps Lock") && caps
						|| getModel().isRollover()) {
					g2d.setPaint(new GradientPaint(0, -5, Color.white, 0, h / 2, backColor));
					g2d.fillRoundRect(0, 0, w, h, 5, 5);
					g2d.setColor(Context.borderColor);
					g2d.drawRoundRect(0, 0, w, h, 5, 5);
				}
				g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);

				Insets insets = getInsets();
				int rw = w - insets.left - insets.right;
				int rh = h - insets.top - insets.bottom;
				int x = insets.left;
				int y = insets.top;

				FontMetrics fm = g2d.getFontMetrics();
				int strWidth = SwingUtilities2.stringWidth(this, fm, text);
				int offsetX = (rw - strWidth) / 2;
				int offsetY = (rh - fm.getHeight()) / 2 + fm.getAscent();
				x = insets.left + offsetX;
				g2d.setColor(Color.black);
				g2d.drawString(text, x, y + offsetY);

				g2d.dispose();
			}

			@Override
			public Dimension getPreferredSize() {
				int minWidth = 0;
				int minHeight = 0;
				Insets insets = getInsets();
				String text = getText();
				FontMetrics fm = getFontMetrics(getFont());
				if (text.length() > 1 || text.equals("←")) {
					int strWidth = SwingUtilities2.stringWidth(this, fm, text);
					minWidth = strWidth;
					minHeight = Math.max(minHeight, fm.getHeight());
					return new Dimension(insets.left + insets.right + minWidth + 5, minHeight + 5);
				} else
					return new Dimension(24, 24);
			}
		}
	}

	class Handler extends MouseInputAdapter implements ActionListener, FocusListener {

		@Override
		public void mousePressed(MouseEvent e) {
			if (onClose(e.getPoint()))
				keyBoard.getParent().setVisible(false);
		}

		@Override
		public void mouseMoved(MouseEvent e) {
			if (e.getSource() == keyBoard) {
				keyBoard.mouseOnClose = onClose(e.getPoint());
				keyBoard.repaint();
			}
		}

		@Override
		public void mouseEntered(MouseEvent e) {
			if (e.getSource() == tf) {
				mouseOver = true;
				CPasswordField.this.repaint();
			}
		}

		@Override
		public void mouseExited(MouseEvent e) {
			if (e.getSource() == tf) {
				mouseOver = false;
				CPasswordField.this.repaint();
			}
		}

		private boolean onClose(Point p) {
			int x = keyBoard.getWidth() - 12, y = 4, w = 12, h = 12;
			Rectangle rect = new Rectangle(x, y, w, h);
			return rect.contains(p);
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			if (e.getSource() == btnKeyboard) {
				JPopupMenu popup = btnKeyboard.getComponentPopupMenu();
				if (!popup.isShowing()) {
					popup.show(btnKeyboard, -160, btnKeyboard.getHeight());
				} else {
				}
			} else {
				String cmd = e.getActionCommand();
				if (cmd.equals("Shift")) {
					keyBoard.shift();
				} else if (cmd.equals("Caps Lock")) {
					keyBoard.caps();
				} else if (cmd.equals("←")) {
					if (tf.getPassword().length > 0)
						try {
							tf.getDocument().remove(tf.getPassword().length - 1, 1);
						} catch (BadLocationException e1) {
							e1.printStackTrace();
						}
				} else {
					if (tf.getPassword().length < 17)
						try {
							tf.getDocument().insertString(tf.getPassword().length, cmd, null);
						} catch (BadLocationException e1) {
							e1.printStackTrace();
						}
				}
			}
		}

		@Override
		public void focusGained(FocusEvent e) {
			tf.repaint();
		}

		@Override
		public void focusLost(FocusEvent e) {
			tf.repaint();
		}
	}

	public static void main(String[] args) {
		JFrame frame = new JFrame();
		frame.add(new JPasswordField());
		frame.pack();
		frame.setVisible(true);
	}
}
